/*
 * Copyright (C) 2008 Peter Kling
 *
 * This file is part of 'A Kind of Billiard', a graphical billiard simulation.
 *
 * 'A Kind of Billiard' is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * 'A Kind of Billiard' is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * 'A Kind of Billiard'. If not, see <http://www.gnu.org/licenses/>.
 */

package cg2.particles;

import javax.media.opengl.GL;

import cg2.mathematics.MathVector;
import cg2.mathematics.Mathematics;

@SuppressWarnings("serial")
public class SmokeParticleEngine extends ParticleEngine {
	
	public SmokeParticleEngine() {
	}

	public SmokeParticleEngine(int numberParticles, double slowDown, double size, double xPos, double yPos, double zPos, double xGravity, double yGravity, double zGravity, int[] randomGravity) {
		super(numberParticles, slowDown, size, xPos, yPos, zPos, xGravity, yGravity, zGravity, randomGravity);
	}
	
	protected Particle[] initializeParticles(){
		Particle[] particles = new Particle[numberParticles];
		for(int i = 0; i < numberParticles;i++){
			particles[i] = new SmokeParticle(this);
			particles[i].setRandomGravity(new int[] {xRandom,yRandom,zRandom});
			particles[i].setXGravity(xGravity);
			particles[i].setYGravity(yGravity);
			particles[i].setZGravity(zGravity);
		}
		return particles;
	}
	
	public void updateParticles(GL gl){
		time = (time + 0.02f) % Math.PI*2;
		// store several OpenGL state variables
		gl.glPushAttrib(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_LIGHTING_BIT | GL.GL_TEXTURE_BIT);
		gl.glPushMatrix();
		
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glDepthMask(false);
		gl.glDisable(GL.GL_LIGHTING);
	    gl.glEnable(GL.GL_BLEND);
	    gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
	    
	    gl.glEnable(GL.GL_TEXTURE_2D);
	    gl.glBindTexture(GL.GL_TEXTURE_2D,textures[0]);
		
		MathVector position;
		double[] viewMatrix = new double[16];
		gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, viewMatrix,0);
		MathVector right = new MathVector(3);
		right.set(0,viewMatrix[0]);
		right.set(1,viewMatrix[4]);
		right.set(2,viewMatrix[8]);

		MathVector up = new MathVector(3);
		up.set(0,viewMatrix[1]);
		up.set(1,viewMatrix[5]);
		up.set(2,viewMatrix[9]);

		// Partikelpumpe
		MathVector addRightUp = Mathematics.add(right,up);
		MathVector subRightUp = Mathematics.sub(right,up);
		MathVector subUpRight = Mathematics.sub(up,right);

		// Move to the right place:
		gl.glTranslated(xPos,yPos,zPos);
		for (int i = 0; i < numberParticles; i++){
			if ( particles[i].isAlive() ){
				double size = particles[i].getSize()/2;
				position = particles[i].getPosition();
				//Setze Farbe des Partikels
				gl.glColor4d(particles[i].getRed(), particles[i].getGreen(), particles[i].getBlue(), particles[i].getLife());
				//Zeichne Partikel
				gl.glBegin(GL.GL_QUADS);
					gl.glTexCoord2d(0,0);
					gl.glVertex3dv(Mathematics.add(position, Mathematics.mul(addRightUp,-size)).toArray(),0);// (x+viewMatrix[0],y+viewMatrix[4],z+viewMatrix[8]);
					gl.glTexCoord2d(1,0);
					gl.glVertex3dv(Mathematics.add(position, Mathematics.mul(subRightUp,size)).toArray(),0);
					gl.glTexCoord2d(1,1);
					gl.glVertex3dv(Mathematics.add(position, Mathematics.mul(addRightUp,size)).toArray(),0);
					gl.glTexCoord2d(0,1);
					gl.glVertex3dv(Mathematics.add(position, Mathematics.mul(subUpRight,size)).toArray(),0);
				gl.glEnd();
				//Update Partikel:
				//Bewegung: Addiere Bewegungsterm mit SlowdownFaktor
								
			}
			particles[i].moveParticle();
		}
		
		// restore saved OpenGL state
		gl.glPopAttrib();
		gl.glPopMatrix();
	
	}
	
	public double getTime(){
		return time;
	}
}
